﻿using System;
using System.Collections.Generic;

namespace Tuxedo.Compile
{
	internal abstract class CodeLine
	{
		public static CodeLine ParseLine(TokenStream tokens)
		{
			switch (tokens.PeekValue())
			{
				case "{": return FakeBlock.Parse(tokens);
				case ";": tokens.Pop(); return null;
				case "if": return IfStatement.Parse(tokens);
				case "for": return ForLoop.Parse(tokens);
				case "do": return DoWhileLoop.Parse(tokens);
				case "while": return WhileLoop.Parse(tokens);
				case "foreach": return ForeachLoop.Parse(tokens);
				case "try": return TryBlock.Parse(tokens);
				case "switch": return SwitchStatement.Parse(tokens);
				case "using": return UsingStatement.Parse(tokens);
				case "lock": return LockStatement.Parse(tokens);
				case "continue": return ContinueStatement.Parse(tokens);
				case "break": return BreakStatement.Parse(tokens);
				case "throw": return ThrowStatement.Parse(tokens);
				case "return": return ReturnStatement.Parse(tokens);

				default:
					VariableDeclaration variableDeclaration = VariableDeclaration.Parse(tokens, true);
					if (variableDeclaration != null)
					{
						return variableDeclaration;
					}

					Expression expression = Expression.ParseExpression(tokens);
					if (expression is AssignmentExpression ||
						expression is FunctionCall ||
						expression is IncrementExpression)
					{
						tokens.PopExpected(";");
						return new WrappedExpression(expression);
					}
					throw new Exception("Can't have loose expressions like this.");
			}
		}

		public static IList<CodeLine> ParseLines(TokenStream tokens)
		{
			List<CodeLine> lines = new List<CodeLine>();

			while (!tokens.IsNext("}"))
			{
				CodeLine line = CodeLine.ParseLine(tokens);
				if (line != null)
				{
					lines.Add(line);
				}
			}

			return lines;
		}

		public static readonly IList<CodeLine> NO_LINES = new CodeLine[0];

		public static IList<CodeLine> ParseBlock(TokenStream tokens, bool bracketsOptional)
		{
			if (bracketsOptional && !tokens.IsNext("{"))
				return tokens.PopIfPresent(";") ? NO_LINES : new List<CodeLine>() { CodeLine.ParseLine(tokens) };

			tokens.PopExpected("{");
			IList<CodeLine> code = CodeLine.ParseLines(tokens);
			tokens.PopExpected("}");
			return code;
		}
	}
}
